package cn.com.infcn.monitor.web;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class RequestCounter implements Cloneable, Serializable {

	private static final long serialVersionUID = -4301825473892026959L;
	private final String name;	//请求路径名称
	private final String id;	//id
	private long hits; // 访问次数
	private long durationsSum; // 响应时间
	private long durationsSquareSum; // 响应时间平方和
	private long maximum; // 响应最长时间
	private long cpuTimeSum; // cpu执行时间和
	private long systemErrors; // 错误次数
	private long responseSizesSum; // 响应数据大小和
	private String stackTrace;	//异常信息

	public RequestCounter(String name, String counterName) {
		super();
		assert name != null;
		assert counterName != null;
		this.name = name;
		this.id = buildId(name, counterName);
	}

	public String getName() {
		return name;
	}

	public String getId() {
		return id;
	}

	public long getHits() {
		return hits;
	}

	public long getDurationsSum() {
		return durationsSum;
	}

	// 平均响应时间
	public int getMean() {
		if (hits > 0) {
			return (int) (durationsSum / hits);
		}
		return -1;
	}

	// 标准偏差
	public int getStandardDeviation() {

		if (hits > 0) {
			return (int) Math.sqrt((durationsSquareSum - (double) durationsSum * durationsSum / hits) / (hits - 1));
		}
		return -1;
	}

	public long getMaximum() {
		return maximum;
	}

	public long getCpuTimeSum() {
		return cpuTimeSum;
	}

	public int getCpuTimeMean() {
		if (hits > 0) {
			return (int) (cpuTimeSum / hits);
		}
		return -1;
	}

	public float getSystemErrorPercentage() {
		if (hits > 0) {
			return Math.min(100f * systemErrors / hits, 100f);
		}
		return 0;
	}

	public int getResponseSizeMean() {
		if (hits > 0) {
			return (int) (responseSizesSum / hits);
		}
		return -1;
	}

	public String getStackTrace() {
		return stackTrace;
	}

	// 添加点击次数
	public void addHit(long duration, long cpuTime, boolean systemError, String systemErrorStackTrace,
			int responseSize) {
		hits++;
		durationsSum += duration;
		durationsSquareSum += duration * duration;
		if (duration > maximum) {
			maximum = duration;
		}
		cpuTimeSum += cpuTime;
		if (systemError) {
			systemErrors++;
		}
		if (systemErrorStackTrace != null) {
			stackTrace = systemErrorStackTrace;
		}
		responseSizesSum += responseSize;
	}
	
	void addHits(RequestCounter request) {
		assert request != null;
		if (request.hits != 0) {
			hits += request.hits;
			durationsSum += request.durationsSum;
			durationsSquareSum += request.durationsSquareSum;
			if (request.maximum > maximum) {
				maximum = request.maximum;
			}
			cpuTimeSum += request.cpuTimeSum;
			systemErrors += request.systemErrors;
			responseSizesSum += request.responseSizesSum;
			if (request.stackTrace != null) {
				stackTrace = request.stackTrace;
			}
		}
	}

	@Override
	public RequestCounter clone() { // NOPMD
		try {
			final RequestCounter clone = (RequestCounter) super.clone();
			return clone;
		} catch (final CloneNotSupportedException e) {
			throw new IllegalStateException(e);
		}
	}

	private static String buildId(String name, String counterName) {
		final MessageDigest messageDigest = getMessageDigestInstance();
		messageDigest.update(name.getBytes());
		final byte[] digest = messageDigest.digest();

		final StringBuilder sb = new StringBuilder(digest.length * 2);
		sb.append(counterName);
		int j;
		for (final byte element : digest) {
			j = element < 0 ? 256 + element : element;
			if (j < 16) {
				sb.append('0');
			}
			sb.append(Integer.toHexString(j));
		}

		return sb.toString();
	}

	private static MessageDigest getMessageDigestInstance() {
		try {
			return MessageDigest.getInstance("SHA-1");
		} catch (final NoSuchAlgorithmException e) {
			throw new IllegalStateException(e);
		}
	}
}
